package com.sbtr.business.classify.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sbtr.business.classify.dto.AlgoTemplateDto;
import com.sbtr.business.classify.entity.AlgoParamVersion;
import com.sbtr.business.classify.entity.AlgoTemplate;
import com.sbtr.business.classify.entity.AlgoTemplateParam;
import com.sbtr.business.classify.mapper.AlgoTemplateMapper;
import com.sbtr.business.classify.service.AlgoParamVersionService;
import com.sbtr.business.classify.service.AlgoTemplateParamService;
import com.sbtr.business.classify.service.AlgoTemplateService;
import com.sbtr.business.utils.ParamExtractorUtils;
import com.sbtr.common.PageDto;
import com.sbtr.controller.classify.AlgoTemplateController;
import com.sbtr.exception.BDException;
import com.sbtr.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 轻量化算法模板(高质量芯片项目) Service接口实现类
 *
 * @author maojianping
 * @since  2023-04-17
 */
@Transactional
@Service
public class AlgoTemplateServiceImpl extends ServiceImpl<AlgoTemplateMapper,AlgoTemplate> implements AlgoTemplateService {

    private Logger logger = LoggerFactory.getLogger(AlgoTemplateServiceImpl.class);

    @Autowired
    AlgoTemplateParamService algoTemplateParamService;

    @Autowired
    AlgoParamVersionService algoParamVersionService;

    @Value("${oss.config.samplePath}")
    private String samplePath; // 系统素材存储目录，yml文件中配置

    private String templateDirName = "algoTemplate"; // 该文件夹在samplePath文件目录下

    @Override
    public PageDto<AlgoTemplate> pageList(AlgoTemplateDto algoTemplateDto) {

        IPage<AlgoTemplate> page = new Page<>();
        page.setSize(algoTemplateDto.getPageSize());
        page.setCurrent(algoTemplateDto.getPage());
        page = baseMapper.selectPages(page, BeanUtil.beanToMap(algoTemplateDto));
        PageDto<AlgoTemplate> r = PageDtoUtils.getPageDtoByIPage(page, AlgoTemplate.class);

        return r;
    }

    @Override
    public AlgoTemplate uploadAndExtractor(AlgoTemplateDto dto, MultipartFile file, String username){

        // 1. 存储文件到对应目录
        String fileName = file.getOriginalFilename();
        String otherName = StringHelper.getNewFileName(fileName);
        String bucketDir = samplePath + File.separator + templateDirName; // 存储目录
        FileHelper.createDir(bucketDir);// 检查并创建存储目录
        AlgoTemplate algoTemplate = BeanCopyUtils.copyProperties(dto, AlgoTemplate.class);
        String fileUrl = bucketDir+File.separator+otherName;
        try{
            file.transferTo(new File(fileUrl)); // 文件保存
        }catch (IOException e){
            throw new BDException("算法模板文件保存出现异常");
        }
        algoTemplate.setAlgoFileParams(username, fileName, otherName, bucketDir);
        // 2.根据当前算法生成默认版本号
        AlgoParamVersion paramVersion = new AlgoParamVersion(username, dto.getId()) ;
        algoParamVersionService.save(paramVersion);
        //3.提取算法模板文件参数信息，并写入默认模板参数列表，提取以变量名称包含"ceprei_param_";的定义信息
        try{
            List<AlgoTemplateParam> list = new ArrayList<>();
            HashMap<String, String> paramMap = ParamExtractorUtils.extractConstants(fileUrl); // 提取
            for(Map.Entry<String, String> entry:paramMap.entrySet())
                list.add(new AlgoTemplateParam(entry.getKey(), entry.getValue(), paramVersion.getId()));

            algoTemplateParamService.saveBatch(list);
        }catch (IOException e){
            throw new BDException("算法模板文件参数提取异常");
        }
        baseMapper.updateById(algoTemplate);
        return algoTemplate;
    }

    /**
     * 根据已有算法模板和参数配置，生成新的算法模板文件
     * @param algoVersionId
     * @return
     */
    @Override
    public AlgoTemplateDto generationAlgoTemplate(Long algoVersionId) {
        // 1.根据当前算法参数版本对象ID查询当前算法参数版本信息
//        String sourceDir = samplePath + File.separator + templateDirName + File.separator; // 算法源文件存储目录
        String sourceDir = FileHelper.buildFIlePath(samplePath, templateDirName); // 算法源文件存储目录
        AlgoParamVersion algoVersion = algoParamVersionService.getById(algoVersionId);
        // 1.1 根据当前算法版本查询相关参数信息并封装
        List<AlgoTemplateParam> algoParamList = algoTemplateParamService.queryList(algoVersionId);
        HashMap<String, String> paramMap = new HashMap<>();
        for(AlgoTemplateParam param:algoParamList){
            paramMap.put(param.getAttribute(), param.getValue());
        }
        //2.根据参数版本对象，查询所属算法模板对象信息
        AlgoTemplate algoTemplate = baseMapper.selectById(algoVersion.getTemplateId());
        //3.copy算法源文件到临时目录文件夹
        AlgoTemplateDto algoDto = BeanCopyUtils.copyProperties(algoTemplate, AlgoTemplateDto.class);
        String tempDirName = DateHelper.geTimeName(algoDto.getAlgoname());
        String destDir = FileHelper.buildFIlePath(sourceDir, tempDirName); // 临时文件生成存储目录
        String srcPath = FileHelper.buildFIlePath(sourceDir, algoDto.getFileaslias()); // 原始算法源文件
        try {
            FileHelper.copyFile(srcPath, destDir);
        } catch (IOException e) {
            throw new BDException("算法原始源文件copy失败");
        }
        //4.拷贝并重命名算法源文件
        String tempSrcUrl = FileHelper.buildFIlePath(destDir, algoDto.getFileaslias());
        String tempDestUrl =FileHelper.buildFIlePath(destDir, algoDto.getFilename());
        String tempDestZipUrl = FileHelper.buildFIlePath(sourceDir, tempDirName+".zip");
        boolean flag = FileHelper.reNameFile(tempSrcUrl, tempDestUrl);
        //5.根据当前算法参数模板信息，进行修改重写算法源文件待改参数
        if(flag){
            try {
                ParamExtractorUtils.writeConstants(tempDestUrl, paramMap);
            } catch (IOException e) {
                throw new BDException("算法复制文件参数更新重写失败");
            }
        }
        // 6.压缩临时copy的算法源文件所在目录，并删除临时目录
        try {
            FileHelper.zipDirectory(destDir, tempDestZipUrl);
            File dirFile = new File(destDir);
            FileHelper.delDirAndContents(dirFile); // 递归删除临时目录
        } catch (IOException e) {
            throw new BDException("算法复制文件打包压缩生成失败");
        }
        //7.构造临时算法模板对象，返回给控制层
        algoDto.setPackageurl(tempDestZipUrl);
        algoDto.setFilename(tempDirName+".zip");
        return algoDto;
    }

    @Override
    public boolean delete(Long id) {
        boolean flag = true;
        try{
            AlgoTemplate template = baseMapper.selectById(id);
            // 1.数据库删除算法相关信息
            // 1.1 根据算法地址：删除算法对应的文件、压缩包等
            baseMapper.deleteById(id);
            // 2.遍历参数历史版本
            List<AlgoParamVersion> paramList = algoParamVersionService.queryList(id);
            for(AlgoParamVersion algoVersion:paramList){
                // 2.1删除参数历史版本;根据参数历史版本对象，删除对应参数集合
                algoParamVersionService.removeById(algoVersion.getId());
            }
            String srcPath = FileHelper.buildFIlePath(samplePath,templateDirName, template.getFileaslias()); // 原始算法源文件
            FileHelper.deleteFile(srcPath); // 算法文件删除
        }catch (Exception e){
            flag = false;
            throw new BDException("删除失败");
        }
        return flag;
    }

    @Override
    public boolean batchDelete(List<Long> listIds) {
        boolean flag = true;
        for(Long id:listIds){
            if(!delete(id)){
                flag = false;
                break;
            }
        }
        return flag;
    }

}

